<template>
  <div class="tree_left">
    <span>全部应用</span>
    <a-button class="actionBtn" type="primary" ghost @click="openAppModal('add')">
      <PlusOutlined />
      新建应用
    </a-button>
  </div>
  <div class="tree_container">
    <a-spin :spinning="loadingTree">
      <a-input
        v-model:value="searchValue"
        allowClear
        class="inputTree"
        placeholder="请输入应用名称、组件名称关键字"
        style="margin-bottom: 16px"
        @change="onSearch"
      >
        <template #prefix>
          <SearchOutlined />
        </template>
      </a-input>
      <div v-if="treeData.length > 0">
        <a-directory-tree
          v-model:expandedKeys="expandedKeys"
          v-model:selectedKeys="selectedKeys"
          blockNode
          :showIcon="false"
          :tree-data="treeData"
          :expandAction="false"
          @select="selectTree"
          :field-names="{
            children: 'components',
            title: 'name',
            key: '_id',
          }"
        >
          <template #title="data">
            <div class="tree_title">
              <div class="tree_title_text ellipsis" :title="data.data.name">
                {{ data.data.name }}
              </div>
              <div class="IconBox">
                <!-- 操作应用 -->
                <template v-if="data.data._type == TypeEnum.app">
                  <EditOutlined
                    class="eidt"
                    style="color: #666666; margin-right: 10px"
                    @click.stop="openAppModal('edit', data.data)"
                    v-if="hasPermission({ objectId: data.data.code, objectType: ResourceType.app, role: Role.manager })"
                  />
                  <PlusCircleOutlined
                    style="color: #666666; margin-right: 10px"
                    @click.stop="openComponentModal('add', data.data)"
                    v-if="hasPermission({ objectId: data.data.code, objectType: ResourceType.app, role: Role.manager })"
                  />
                  <MinusCircleOutlined
                    style="color: #666666"
                    @click.stop="openDeleteModel(data.data)"
                    v-if="hasPermission({ objectId: data.data.code, objectType: ResourceType.app, role: Role.manager })"
                  />
                </template>
                <!-- 操作组件 -->
                <template v-if="data.data._type == TypeEnum.component">
                  <EditOutlined
                    class="eidt"
                    style="color: #666666; margin-right: 10px"
                    @click.stop="editComponent('edit', data.data)"
                    v-if="
                      hasPermission([
                        { objectId: data.data.code, objectType: ResourceType.component, role: Role.manager },
                        { objectId: data.data.applicationCode, objectType: ResourceType.app, role: Role.manager },
                      ])
                    "
                  />
                  <MinusCircleOutlined
                    style="color: #666666; margin-right: 10px"
                    @click.stop="openDeleteModel(data.data)"
                    v-if="
                      hasPermission([
                        { objectId: data.data.code, objectType: ResourceType.component, role: Role.manager },
                        { objectId: data.data.applicationCode, objectType: ResourceType.app, role: Role.manager },
                      ])
                    "
                  />
                </template>
              </div>
            </div>
          </template>
        </a-directory-tree>
      </div>
      <BasicEmpty v-else />
    </a-spin>
  </div>

  <BasicModal
    ref="addApplicationRef"
    :title="`${modalType == 'add' ? '新建' : '编辑'}应用`"
    width="400px"
    :confirmLoading="editAppLoading"
    @emit-callback-fn="addCallbackFn($event, addApplicationRef, formRef)"
  >
    <template #content>
      <SchemaForm />
    </template>
  </BasicModal>
  <BasicModal
    ref="addComponentRef"
    :confirmLoading="editComponentLoading"
    :title="`${modalType == 'add' ? '新建' : '编辑'}组件`"
    @emit-callback-fn="addComponent($event)"
  >
    <template #content>
      <NavTitle title="基本信息" showRightIcon class="navTitle" />
      <ComponentForm ref="ComponentFromRef" />
      <NavTitle title="开发信息" showRightIcon class="navTitle" />
      <DevelopForm ref="DevelopFromRef" />
    </template>
  </BasicModal>
  <BasicModal
    ref="deleteComponentRef"
    title="提示"
    :confirmLoading="editAppLoading"
    width="400px"
    :propsTips="`你确定要删除该${
      deleteType == TypeEnum.app ? '应用？删除后该应用数据，将被清除！' : '组件？删除后该组件数据，将被清除！'
    }`"
    @emit-callback-fn="addCallbackFn($event, deleteComponentRef)"
  >
    <template #content="slotProps">
      <div class="delete_code">
        {{ deleteType == TypeEnum.app ? '应用编码' : '组件编码' }}: {{ slotProps?.data?.code }}
      </div>
      <a-form
        ref="formDataRef"
        name="advanced_search"
        label-align="right"
        class="ant-advanced-search-form"
        :model="formState"
      >
        <a-row :gutter="24">
          <a-col :span="24">
            <a-form-item label="验证信息" name="deleteValue" :rules="rulesFun(slotProps?.data?.code)">
              <a-textarea
                v-model:value="formState.deleteValue"
                :placeholder="`${deleteType == TypeEnum.app ? '请输入应用编码' : '请输入组件编码'}`"
                @paste="handleFalse"
                @copy="handleFalse"
                @cut="handleFalse"
              />
            </a-form-item>
          </a-col>
        </a-row>
      </a-form>
    </template>
  </BasicModal>
</template>

<script setup lang="ts">
import { useEditTree } from '../hooks/index';
import {
  SearchOutlined,
  EditOutlined,
  PlusCircleOutlined,
  MinusCircleOutlined,
  PlusOutlined,
} from '@ant-design/icons-vue';

import { useForm } from '@/components/SchemaForm/index';
import type { FormSchema } from '@/components/SchemaForm';
import { componentData, languageOptinos } from '@/settings/commonSettings';
import {
  addApplicationFun,
  deleteApplicationFun,
  putApplicationFun,
  addComponentData,
  deleteComponentData,
  putComponentData,
} from '@/api/applicationManagement';
import { validatorCode, validatorCodeOrName, validatorHttpUrl } from '@/settings/commonSettings';
import { PordDefaultData } from '@/enums/commonEnum';
import { ResourceType, Role, TypeEnum } from '@/enums/pipelineEnum';
import { usePermissionStore } from '@/store/modules/permission';
import { usePermission } from '@/hooks/web/usePermission';
import { useApplicationStore } from '@/store/modules/app';
import { storeToRefs } from 'pinia';
import { message } from 'ant-design-vue';
const counterStore = useApplicationStore();
const { setExpandedId, setSelectedId } = counterStore;
const { expandedId, selectedId } = storeToRefs(counterStore);
const { hasPermission } = usePermission();
const permStore = usePermissionStore();
//新增||编辑应用form
const [SchemaForm, formRef] = useForm({
  schemas: [
    {
      field: 'name',
      label: '应用名称',
      labelWidth: 90,

      colProps: {
        span: 24,
      },
      rules: [
        {
          required: true,
          validator: (_, value: any) => {
            return new Promise((resolve, reject) => {
              if (!value) {
                reject(new Error('应用名称不能为空'));
              } else if (value.length > 20) {
                reject(new Error('请输入20字符以内的应用名称'));
              } else {
                resolve();
              }
            });
          },
        },
      ],
      component: 'Input',
    },
    {
      field: 'code',
      label: '应用编码',
      labelWidth: 90,
      maxLength: 50,
      colProps: {
        span: 24,
      },
      rules: [
        {
          required: true,
          validator: (_, value: any) => {
            return new Promise((resolve, reject) => {
              if (!value) {
                reject(new Error('应用编码不能为空'));
              } else if (!validatorCode.test(value)) {
                reject(new Error('请输入长度不超过50字符的小写字母、数字或中划线，且不能以中划线开头或结尾。'));
              } else {
                resolve();
              }
            });
          },
        },
      ],
      component: 'Input',
    },
    {
      field: 'description',
      label: '应用描述',
      labelWidth: 90,
      required: false,
      colProps: {
        span: 24,
      },
      component: 'InputTextArea',
    },
  ] as FormSchema[],
});

const formState = reactive({
  deleteValue: '',
});

const rulesFun = (code: string) => {
  return [
    {
      required: true,
      validator: (_: any, value: any) => {
        return new Promise<void>((resolve, reject) => {
          if (value !== code) {
            reject(new Error('请输入编码'));
          } else {
            resolve();
          }
        });
      },
    },
  ];
};

const handleFalse = (e: any) => {
  e.preventDefault();
};

//组件-基本信息
const [ComponentForm, ComponentFromRef] = useForm({
  schemas: [
    {
      field: 'name',
      label: '组件名称',
      labelWidth: 120,
      colProps: {
        span: 12,
      },
      rules: [
        {
          required: true,
          validator: (_, value: any) => {
            return new Promise((resolve, reject) => {
              if (!value) {
                reject(new Error('组件名称不能为空'));
              } else if (value.length > 20) {
                reject(new Error('请输入20字符内的组件名称'));
              } else {
                resolve();
              }
            });
          },
        },
      ],
      component: 'Input',
    },
    {
      field: 'code',
      label: '组件编码',
      labelWidth: 120,
      colProps: {
        span: 12,
      },
      rules: [
        {
          required: true,
          validator: (_, value: any) => {
            return new Promise((resolve, reject) => {
              if (!value) {
                reject(new Error('组件编码不能为空'));
              } else if (!validatorCode.test(value)) {
                reject(new Error('请输入长度不超过50字符的小写字母、数字或中划线，且不能以中划线开头或结尾。'));
              } else {
                resolve();
              }
            });
          },
        },
      ],
      component: 'Input',
    },
    {
      field: 'componentType',
      label: '组件类型',
      labelWidth: 120,
      colProps: {
        span: 12,
      },
      componentProps: {
        options: componentData,
      },
      defaultValue: 1,
      required: true,
      component: 'RadioGroup',
    },
    {
      field: 'programLanguage',
      label: '编程语言',
      labelWidth: 120,
      required: true,
      colProps: {
        span: 12,
      },
      componentProps: {
        options: languageOptinos,
        placeholder: '请选择编程语言',
      },
      defaultValue: 'nodeJs',
      component: 'Select',
    },
  ] as FormSchema[],
});

//组件-开发信息
const [DevelopForm, DevelopFromRef] = useForm({
  schemas: [
    {
      field: 'codeRepository',
      label: '代码仓库',
      labelWidth: 120,
      required: true,
      colProps: {
        span: 12,
      },
      rules: [
        {
          required: true,
          validator: (_, value: any) => {
            return new Promise((resolve, reject) => {
              if (!value) {
                reject(new Error('代码仓库不能为空'));
              } else if (!validatorHttpUrl.test(value)) {
                reject(new Error('请输入http://或者https://开头的仓库地址'));
              } else {
                resolve();
              }
            });
          },
        },
      ],
      component: 'Input',
    },
    {
      field: 'gitToken',
      label: 'git凭证token',
      labelWidth: 120,
      required: true,
      colProps: {
        span: 12,
      },
      rules: [
        {
          required: true,
          validator: (_, value: any) => {
            return new Promise((resolve, reject) => {
              if (!value) {
                reject(new Error('git凭证token不能为空'));
              } else if (!validatorCodeOrName.test(value)) {
                reject(new Error('请输入数字、字母、中划线或下划线组合的git凭证token'));
              } else {
                resolve();
              }
            });
          },
        },
      ],
      component: 'Input',
    },
  ] as FormSchema[],
});

const { searchValue, onSearch, expandedKeys, selectedKeys, getTreeData, treeData, selectNode, loadingTree } =
  useEditTree(TypeEnum);
const emits = defineEmits(['selectTreeNode', 'updateDetail']);

const editAppLoading = ref<boolean>(false);
const editComponentLoading = ref<boolean>(false);

const addApplicationRef = ref();
const addComponentRef = ref();
const deleteComponentRef = ref();
const modalType = ref('add');

const openAppModal = (type: string, data?: any) => {
  modalType.value = type;
  if (type == 'edit') {
    nextTick(() => {
      formRef.setFieldsValue(data);
      formRef.updateSchema({
        field: 'code',
        label: '应用编码',
        labelWidth: 90,
        required: true,
        componentProps: { disabled: true },
        colProps: {
          span: 24,
        },
        component: 'Input',
      });
    });
  }
  addApplicationRef.value.showModal(data);
};
//打开组件操作弹窗
const openComponentModal = (type: string, data?: any) => {
  modalType.value = type;
  addComponentRef.value.showModal(data);
};

const deleteType = ref(TypeEnum.app);
const openDeleteModel = (data: any) => {
  deleteType.value = data._type;
  modalType.value = 'delete';
  formState.deleteValue = '';
  deleteComponentRef.value.showModal(data);
};

//确认，关闭弹窗
const addCallbackFn = async (evt: any, modalRef: any, fromRef?: any) => {
  if (modalType.value == 'delete') {
    if (deleteType.value == TypeEnum.app) {
      deleteApplication(evt.propsData.code);
    } else {
      deleteComponent(evt.propsData);
    }
    return;
  }
  const res = await fromRef.validate();
  if (res) {
    modalType.value == 'add' && addApp(res);
    modalType.value == 'edit' && editApp(res, evt.propsData);
  }
};

//编辑应用
const editApp = async (form: any, evt?: any) => {
  editAppLoading.value = true;
  const data = { ...form, projectCode: PordDefaultData.projectCode };
  await putApplicationFun(data)
    .then(() => {
      message.success('编辑成功');
      handleTreeData(evt._id);
      addApplicationRef.value.hideModal();
    })
    .finally(() => {
      editAppLoading.value = false;
    });
};

//新增应用
const addApp = async (form: any) => {
  editAppLoading.value = true;
  const data = { ...form, projectCode: PordDefaultData.projectCode };
  await addApplicationFun(data)
    .then(() => {
      message.success('新增成功');
      handleTreeData(`app_id${form.code}`);
      addApplicationRef.value.hideModal();
      permStore.fetchPermissionList();
    })
    .finally(() => {
      editAppLoading.value = false;
    });
};

const formDataRef = ref<any>();
//删除应用
const deleteApplication = async (code: number | string) => {
  formDataRef.value
    .validate()
    .then(async () => {
      editAppLoading.value = true;
      await deleteApplicationFun(code)
        .then(() => {
          handleTreeData();
          message.success('删除成功');
          deleteComponentRef.value.hideModal();
        })
        .finally(() => {
          editAppLoading.value = false;
        });
    })
    .catch((err: any) => {
      console.log('error', err);
    });
};

//新增组件
const addComponent = async (obj: any) => {
  let res2: any = null;
  const res1 = await ComponentFromRef.validate().finally(async () => {
    res2 = await DevelopFromRef.validate();
  });
  let data = {
    ...res1,
    ...res2,
  };
  editComponentLoading.value = true;
  if (modalType.value == 'add') {
    data = { ...data, applicationCode: obj.propsData.code };
    await addComponentData(data)
      .then(() => {
        message.success('新增成功');
        handleTreeData(`components_id${data.applicationCode}${data.code}`, obj.propsData._id);
        addComponentRef.value.hideModal();
      })
      .finally(() => {
        editComponentLoading.value = false;
      });
  }

  if (modalType.value == 'edit') {
    data = { ...data, applicationCode: obj.propsData.applicationCode, label: obj.propsData.label };
    await putComponentData(data)
      .then(() => {
        message.success('编辑成功');
        handleTreeData(`components_id${data.applicationCode}${data.code}`, `app_id${obj.propsData.applicationCode}`);
        addComponentRef.value.hideModal();
      })
      .finally(() => {
        editComponentLoading.value = false;
      });
  }
};

//编辑组件
const editComponent = async (type: string, data?: any) => {
  modalType.value = type;
  nextTick(() => {
    ComponentFromRef.setFieldsValue({ ...data });
    DevelopFromRef.setFieldsValue({ ...data });
    ComponentFromRef.updateSchema({
      field: 'code',
      label: '组件编码',
      labelWidth: 120,
      required: true,
      colProps: {
        span: 12,
      },
      componentProps: { disabled: true },
      component: 'Input',
    });
  });

  addComponentRef.value.showModal(data);
};

//删除组件
const deleteComponent = (obj: any) => {
  console.log(obj);
  formDataRef.value
    .validate()
    .then(async () => {
      editAppLoading.value = true;
      await deleteComponentData(obj.label)
        .then(() => {
          // 删除组件之后选中组件的应用
          message.success('删除成功');
          handleTreeData(`app_id${obj.applicationCode}`, `app_id${obj.applicationCode}`);
          deleteComponentRef.value.hideModal();
        })
        .finally(() => {
          editAppLoading.value = false;
        });
    })
    .catch((err: any) => {
      console.log('error', err);
    });
};

//点击选中树节点
const selectTree = (data: any, e: any) => {
  selectNode.value = e.node;
};

// id = 新增节点的app_id, appId = 展开的节点app_id
const handleTreeData = async (id?: string, appId?: string) => {
  await getTreeData(id, appId);
  emits('updateDetail', treeData.value);
};

const appCode = ref<string>('');
onBeforeMount(async () => {
  appCode.value = sessionStorage.getItem('appCode_id') || '';
  if (appCode.value) {
    await getTreeData(appCode.value as string, appCode.value as string);
    openComponentModal('add', selectNode.value);
    sessionStorage.setItem('appCode_id', '');
  } else if (selectedId.value) {
    await getTreeData(selectedId.value, expandedId.value);
  } else {
    await getTreeData();
  }
  emits('updateDetail', treeData.value);
});

onUnmounted(() => {
  setExpandedId(expandedKeys.value.toString());
  setSelectedId(selectedKeys.value.toString());
});

watch(
  () => selectNode.value,
  (val) => {
    emits('selectTreeNode', val);
  },
  {
    deep: true,
  },
);
</script>

<style lang="less" scoped>
.tree_left {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.tree_container {
  margin-top: 16px;
  width: 100%;
}

.tree_title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 32px;
  line-height: 32px;
  &_text {
    width: 155px;
    height: 100%;
  }

  .IconBox {
    display: none;
    margin-left: 10px;
    :deep(span[role]):hover {
      color: #2590ff !important;
      background-color: #daecff;
    }
  }
  &:hover {
    .IconBox {
      display: flex;
    }
  }
}
:deep(.ant-tree-switcher) {
  height: 32px;
  line-height: 32px;
}

:deep(.ant-tree-treenode) {
  padding: 0;
}
:deep(.ant-tree-treenode:hover) {
  background-color: #eef7ff;
  border-radius: 4px;
  height: 32px;
  line-height: 32px;
}

:deep(.ant-tree.ant-tree-directory .ant-tree-treenode:hover::before) {
  background-color: #eef7ff;
  height: 32px;
  line-height: 32px;
  .ant-tree-node-selected {
    color: black !important;
  }
}

:deep(.ant-tree-treenode-selected) {
  background-color: #2590ff !important;
  border-radius: 4px;
  padding: 0;
}
:deep(.ant-tree-treenode-selected:hover::before) {
  background-color: transparent !important;
  border-radius: 4px;
}
:deep(.ant-tree-treenode-selected::before) {
  background-color: transparent !important;
}

.navTitle {
  margin-bottom: 24px;
}

.delete_code {
  margin-bottom: 20px;
  font-size: 14px;
  font-weight: bold;
}
</style>
